<?php
/**
 * Created by PhpStorm.
 * User: LRChang
 * Date: 2018/6/5
 * Time: 16:24
 * Mail: hjklrchang@qq.com
 */

namespace app\adminapi\model;

use app\adminapi\filter\RoleFilter;
use app\base\exception\BaseException;
use app\base\exception\RecordNotFoundException;
use traits\model\SoftDelete;
class Role extends Common
{
    use SoftDelete;
    protected $deleteTime = 'delete_time';

    const SUPER_ADMIN_ROLE_ID = 1; //超级管理员
    const COMPANY_ADMIN_ROLE_ID = 29; // 单位端超级管理员
    const DRIVER_ROLE_ID = 5;  // 司机
    const PASSENGER_ROLE_ID = 2; // 乘客

    // 公共角色
    const PUBLIC_ROLES = [
        self::DRIVER_ROLE_ID,
        self::PASSENGER_ROLE_ID
    ];

    /**
     * 获取角色列表
     * @param $where
     * @param $fields
     * @param int $page
     * @param int $pagenum
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function listData($where, $fields, $page = 1, $pagenum = 20) {
        $filter = new RoleFilter($fields, $where);
        $condition = $filter->geFiltered();
        $where = $condition['where'];
        $fields = $condition['field'];
        $mark = $filter->getMark();

        // 闭包查询
        $buildQuery = function($query) use ($where) {
            // 与company_id组合条件
            $addition = function($query, $field, $value){
                $query->where($field, $value)->whereOr('role_id', 'IN', self::PUBLIC_ROLES);
            };

            self::authCompanyQuery($query, $where, 'company_id', $addition);
        };

        $result = [];
        $result['count'] = $this->where($buildQuery)->count();
        $result['list'] = $this->where($buildQuery)
            ->page($page, $pagenum)
            ->field($fields)
            ->order('role_id desc')
            ->select();

        return array_merge($result, $mark);
    }

    /**
     * 新增或者编辑角色
     * @param $params
     * @return $this|false|int
     * @throws BaseException
     * @throws RecordNotFoundException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function createOrUpdate($params) {
        // 超级管理员可编辑角色
        // 单位超级管理员可编辑该单位的角色
        $user = new User();
        $session = $user->getLoginUser();
        $this->checkAdminAuth($session, self::AUTH_SCOPE_EITHER);

        if(isset($params['role_id'])) {
            $where = ['role_id' => $params['role_id']];
            $buildQuery = function($query) use ($where) {
                self::authCompanyQuery($query, $where, 'company_id', null, true);
            };

            $role = self::get($buildQuery);
            if(!$role) {
                throw new RecordNotFoundException();
            }

        }elseif (!self::isSuperAdmin($session) && $session['user']['company_id']) {
            $params['company_id'] = $session['user']['company_id'];
        }

        // 单位端管理员新增与编辑的角色所属单位永远是本单位
        if(!self::isSuperAdmin($session)){
            $params['company_id'] = $session['company']['company_id'];
        }

        // 验证单位是否存在
        if($params['company_id'] > 0){
            $this->addRelativeFields( $params, 'app\adminapi\model\Company', $params['company_id'],  [], '关联单位不存在');
        }

        // 验证单位端管理员给的权限有无超出他本身的权限
        if(!self::isSuperAdmin($session) && !empty($params['menus'])){
            $authoMenus = $this->getRoleMenusIDs($session['user']['role_id']);
            $menus = explode(',', $params['menus']);
            foreach($menus as $item){
                if(!in_array(intval($item), $authoMenus)){
                    throw new BaseException("菜单[{$item}]超出权限范围");
                }
            }
        }

        if(isset($params['role_id'])) {
            return $this->isUpdate(true)->save($params);
        }

        $this->data($params)->save();
        return $this;
    }

    /**
     * 获取菜单树
     * @param $role_id
     * @param $module_type
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function getRoleMenusTree($role_id, $module_type = null){
        $menus = $this->getRoleMenusList($role_id, $module_type);
        $list = [];

        foreach($menus as $item){
            $list[] = $item->toArray();
        }

        return Arr2Tree($list);
    }

    /**
     * 获取角色的权限
     * @param $role_id
     * @return array|null
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function getAccess($role_id){
        $menus = $this->getRoleMenusList($role_id);

        $access = [];
        foreach($menus as $item){
            $url = $item->getAttr('url');
            if($url && $url !== '#'){
                array_push($access, strtolower($url));
            }
        }

        return empty($access) ? NULL : $access;
    }

    /**
     * 获取角色可访问菜单
     * @param $role_id
     * @param $module_type
     * @return false|null|\PDOStatement|string|\think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function getRoleMenusList($role_id, $module_type = null){
        $role_ids = explode(',', $role_id);
        if(empty($role_ids)) return NULL;

        $where = [];
        if($module_type !== null){
            $where['module_type'] = $module_type;
        }

        if(!in_array(strval(self::SUPER_ADMIN_ROLE_ID), $role_ids)){
            $roles = $this->where(['role_id' => ['IN', $role_ids], 'state' => 1])->select();
            $menus = [];
            foreach($roles as $role){
                $menu = $role->getAttr('menus');
                $menus = array_merge($menus, explode(',', $menu));
            }

            array_unique($menus);
            $menus = array_filter($menus);
            if(empty($menus)) return NULL;

            $where['id'] = ['IN', $menus];
            $where['state'] = 1;
        }

        return (new Menu())->where($where)->select();
    }

    /**
     * 获取菜单id数组
     * @param $role_id
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function getRoleMenusIDs($role_id){
        $menus = $this->getRoleMenusList($role_id);

        $ids = [];
        foreach($menus as $item){
            array_push($ids, $item->getAttr('id'));
        }

        return $ids;
    }
}